/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controladoras.negocio;
import comandos.CmdBD;
import comandos.Del.CmdDelClienteHasReserva;
import comandos.Del.CmdDelReserva;
import comandos.Del.CmdDelVooHasReserva;
import comandos.Ins.CmdInsClienteHasReserva;
import comandos.Ins.CmdInsReserva;
import comandos.Ins.CmdInsVooHasReserva;
import comandos.Sel.CmdSelClienteHasReserva;
import comandos.Sel.CmdSelReserva;
import comandos.Sel.CmdSelSequence;
import comandos.Sel.CmdSelVoo;
import comandos.Up.CmdUpVooHasReserva;
import comandos.Sel.CmdSelVooHasReserva;
import comandos.Up.CmdUpSequence;
import comandos.Up.CmdUpVoo;
import entidades.Cliente;
import interfaces.IGerenciaReserva;
import erros.ErroPersistencia;
import entidades.Reserva;
import erros.ErroAtualizacao;
import erros.ErroCadastramento;
import erros.ErroRecuperacao;
import erros.ErroRemocao;
import interfaces.IPersistencia;
import java.util.ArrayList;
import entidades.Voo;

/**
 * Classe que codifica a controladora de negócio da entidade reserva.
 * @author Daniel
 * @author Lucas
 */
public class CntrGerenciaReserva implements IGerenciaReserva {
    /**
     * Referência para o singleton da controladora de negócio
     * da entidade reserva.
     */
    private static CntrGerenciaReserva ref;
    /**
     * Referência para a controladora de persistência associada
     * à controladora de negócio.
     */
    private IPersistencia cntrPersistencia;

    /**
     * Cadastra uma reserva no banco de dados.
     * @param reserva Reserva à ser cadastrada no banco.
     * @param cliente cliente o qual esta realizando a reserva.
     * @throws ErroCadastramento Lança a exceção do cadastramento em
     * caso de falha.
     */
    @Override
    public void cadastrarReserva(final Cliente cliente, final Reserva reserva)
            throws ErroCadastramento {

        try {
            ArrayList<Reserva> lista = recuperarReservas(cliente);
            if(lista.size()>=2){
                throw new ErroCadastramento("O usuário já possui o número" +
                        " máximo de reserva");
            }

        } catch(ErroRecuperacao e) {
            throw new ErroCadastramento("Erro de recuperação " +
                    "das reservas do cliente");
        }

        try{
            if(reserva.getNroVoosReserva() > 5 ||
                    reserva.getNroVoosReserva() <1 ) {
                throw new ErroCadastramento("numero de vôos invalidos " +
                            "para essa reserva");
           }
           CntrGerenciaVoo cntrGerenciaVoo = CntrGerenciaVoo.instanciar();
           for(int i = 0; i < reserva.getNroVoosReserva(); i++) {
               Voo vooRecuperado;
               try {
                   vooRecuperado = cntrGerenciaVoo.recuperarVoo(
                           reserva.getReservaVoo(i));
                   reserva.setReservaVoo(i, vooRecuperado);

               } catch (ErroRecuperacao e) {
                   throw new ErroCadastramento("Não foi possível" +
                           " cadastrar " +
                           "essa reserva, vôo não achado no banco");
               }
           }
           for(int j = 0 ; j < reserva.getNroVoosReserva(); j++){
                if(reserva.getReservaVoo(j).getVagas()==0){
                    throw new ErroCadastramento("Não ha vagas para esse " +
                                " voo");
                }
            }
           for(int j = 0 ; j < reserva.getNroVoosReserva(); j++){
                reserva.getReservaVoo(j).adicionaPassageiro();
            }

            int idAntigo;
            int idNovo;
            String temp;
            String idNovoStr;
            String idAntigoStr;
            CmdBD comando  = new CmdSelSequence();
            temp = (String) cntrPersistencia.executar(comando);
            idAntigo = Integer.parseInt(temp);
            idNovo = idAntigo == 99999 ? 10000 : idAntigo+1;
            idAntigoStr = temp;
            idNovoStr = String.valueOf(idNovo);

            reserva.setReserva(idNovoStr);
            comando = new CmdUpSequence(idAntigoStr, idNovoStr);
            cntrPersistencia.executar(comando);
            comando = new CmdInsReserva(reserva);
            cntrPersistencia.executar(comando);
            comando = new CmdInsClienteHasReserva(cliente, reserva);
            cntrPersistencia.executar(comando);
            for(int i = 0; i<reserva.getNroVoosReserva(); i++){
                Voo v = reserva.getReservaVoo(i);
                comando = new CmdInsVooHasReserva(v, reserva);
                cntrPersistencia.executar(comando);
            }
            for(int i = 0; i<reserva.getNroVoosReserva(); i++){
                Voo v = reserva.getReservaVoo(i);
                comando = new CmdUpVoo(v, v);
                cntrPersistencia.executar(comando);
            }
        } catch (ErroPersistencia e) {
            throw new ErroCadastramento("Erro de cadastramento da reserva");
        }

    }
    /**
     * Recupera uma reserva do banco de dados.
     * @param reserva Reserva à ser recuperada do banco.
     * @return Retorna a reserva recuperada.
     * @throws ErroRecuperacao Lança exceção de recuperação
     * em caso de falha.
     */
    @Override
    public Reserva recuperarReserva(Reserva reserva) throws ErroRecuperacao {
        try{
            CmdBD comando = new CmdSelReserva(reserva);
            reserva = (Reserva) cntrPersistencia.executar(comando);
            comando = new CmdSelVooHasReserva(reserva);
            ArrayList<Voo> lista =
                    (ArrayList<Voo>)cntrPersistencia.executar(comando);
            for(int i = 0; i < lista.size(); i++) {
                comando = new CmdSelVoo(lista.get(i));
                ArrayList<Voo> v =
                        (ArrayList<Voo>) cntrPersistencia.executar(comando);
                reserva.adicionaVoo(v.get(0));
            }
            return reserva;
        } catch (ErroPersistencia e){
            throw new ErroRecuperacao("Erro de recuperação da reserva");
        }
    }
    /**
     * Deleta uma reserva do banco de dados.
     * @param reserva Reserva à ser deletada do banco.
     * @param cliente cliente o qual deseja deletar sua reserva.
     * @throws ErroRemocao Lança a exceção de remoção em caso de falha.
     */
    @Override
    public void delReserva(Cliente cliente,Reserva reserva) throws ErroRemocao {
        try{
            CmdBD comando = new CmdDelReserva(reserva);
            cntrPersistencia.executar(comando);
            comando = new CmdDelClienteHasReserva(reserva);
            cntrPersistencia.executar(comando);
            comando = new CmdDelVooHasReserva(reserva);
            cntrPersistencia.executar(comando);
            for(int i = 0; i < reserva.getNroVoosReserva(); i++){
                reserva.getReservaVoo(i).retiraPassageiro();
            }
            for(int i = 0; i<reserva.getNroVoosReserva(); i++){
                Voo v = reserva.getReservaVoo(i);
                comando = new CmdUpVoo(v, v);
                cntrPersistencia.executar(comando);
            }
        } catch(ErroPersistencia erro) {
            throw new ErroRemocao("Erro na remoção da reserva");
        }

    }
    /**
     * Atualiza uma reserva no banco de dados.
     * @param reserva Reserva à ser atualiza.
     * @param reservaNova Novos atributos da reserva
     * @throws ErroAtualizacao Lança a exceção de atualização
     */
    @Override
    public void atualizarReserva(Reserva reserva,
            Reserva reservaNova) throws ErroAtualizacao{
        try{
            CmdBD comando;
            for(int i = 0; i < reservaNova.getNroVoosReserva(); i++) {
                comando = new CmdSelVoo(reservaNova.getReservaVoo(i));
                ArrayList<Voo> lista =
                        (ArrayList<Voo>) cntrPersistencia.executar(comando);
                if(lista.size() == 0) {
                    throw new ErroAtualizacao("Voo nao existe no banco.");
                }
            }
            for(int i=0;i<reservaNova.getNroVoosReserva();i++) {
                comando = new CmdUpVooHasReserva(reserva.getReservaVoo(i),
                        reservaNova.getReservaVoo(i));
                cntrPersistencia.executar(comando);
            }
        } catch (ErroPersistencia e) {
            throw new ErroAtualizacao("Erro na atualizacao da reserva");
        }
    }

    /**
     * Retorna as reservas de um determinado cliente.
     * @param cliente Cliente à ter as suas reservas retornada.
     * @return Retorna a lista de reservas de um cliente.
     * @throws ErroRecuperacao lança erro de recuperação em caso de falha.
     */
    @Override
    public ArrayList<Reserva> recuperarReservas(Cliente cliente)
            throws ErroRecuperacao {
        try {
            CmdBD comando = new CmdSelClienteHasReserva(cliente);
            ArrayList<Reserva> listaReservas = (ArrayList<Reserva>)
            cntrPersistencia.executar(comando);
            for(int i = 0;i < listaReservas.size(); i++ ) {
                comando = new CmdSelVooHasReserva(listaReservas.get(i));
                ArrayList<Voo> listaVoo = (ArrayList<Voo>)
                        cntrPersistencia.executar(comando);
                for(int j = 0 ; j < listaVoo.size(); j++) {
                    comando = new CmdSelVoo(listaVoo.get(j));
                    ArrayList<Voo> v =
                        (ArrayList<Voo>) cntrPersistencia.executar(comando);
                    (listaReservas.get(i)).adicionaVoo(v.get(0));
                }
            }
            return listaReservas;
        } catch (ErroPersistencia e) {
            throw new ErroRecuperacao("Não foi possível recuperar as " +
                    "reservas do cliente");
        }
    }



    /**
     * Instancia o singleton da controladora de negócio da entidade reserva.
     * @return retorna a referência para o singleton da controladora.
     */
    public static CntrGerenciaReserva instanciar() {
        if (ref == null) {
            ref = new CntrGerenciaReserva();
        }
        return (ref);
    }

    /**
     * Seta a controladora de persistência associada
     * à essa controladora
     * @param cntr controladora de persistência a ser associada.
     */
    public void setCntrPersistencia(IPersistencia cntr) {
        cntrPersistencia = cntr;
    }
}
